/*
 * This file is part of HE_Mesh, a library for creating and manipulating meshes.
 * It is dedicated to the public domain. To the extent possible under law,
 * I , Frederik Vanhoutte, have waived all copyright and related or neighboring
 * rights.
 * 
 * This work is published from Belgium. (http://creativecommons.org/publicdomain/zero/1.0/)
 * 
 */
package wblut.hemesh;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.zip.GZIPOutputStream;

import gnu.trove.map.TLongIntMap;
import gnu.trove.map.hash.TLongIntHashMap;

/**
 *
 */
public class HET_WriterWRL {

	/**
	 *
	 *
	 * @param mesh
	 * @param path
	 * @param name
	 */
	public static void saveMeshWithFaceColor(final HE_Mesh mesh,
			final String path, final String name) {
		try {
			saveMeshWithFaceColor(mesh, createOutputStream(new File(path, name
					+ ".wrl")));
		} catch (final IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 *
	 *
	 * @param mesh
	 * @param stream
	 */
	public static void saveMeshWithFaceColor(final HE_Mesh mesh,
			final OutputStream stream) {
		try {
			final BufferedOutputStream out = new BufferedOutputStream(stream,
					0x20000);
			out.write("#VRML V2.0 utf8\n".getBytes());
			out.write("#Generated by HE_Mesh 2014 http://hemesh.wblut.com\n"
					.getBytes());
			out.write("\n".getBytes());
			out.write("Shape {\n".getBytes());
			out.write("\tappearance Appearance {\n".getBytes());
			out.write("\t\tmaterial Material {\n".getBytes());
			out.write("\t\t}  #Material\n".getBytes());
			out.write("\t} #Appearance\n".getBytes());
			out.write("\tgeometry IndexedFaceSet {\n".getBytes());
			out.write("\t\tcoord  DEF AllCoords Coordinate {\n".getBytes());
			out.write("\t\tpoint [\n".getBytes());
			// list vertices coordinates
			final TLongIntMap vertexKeys = new TLongIntHashMap(10, 0.5f, -1L,
					-1);
			int counter = 0;
			final HE_VertexIterator vItr = mesh.vItr();
			HE_Vertex v;
			while (vItr.hasNext()) {
				v = vItr.next();
				out.write(("\t\t\t" + v.xf() + " " + v.yf() + " " + v.zf() + ",\n")
						.getBytes());
				vertexKeys.put(v.key(), counter);
				counter++;
			}
			out.write("\t\t] #point\n".getBytes());
			out.write("\t\t} #Coordinate\n".getBytes());
			out.write("\t\tcoordIndex [\n".getBytes());
			// list faces vertices indexes
			counter = 0;
			HE_FaceIterator fItr = mesh.fItr();
			HE_Face f;
			List<HE_Vertex> vlist;
			while (fItr.hasNext()) {
				f = fItr.next();
				vlist = f.getFaceVertices();
				if (vlist.size() == 3) {
					out.write(("\t\t\t" + vertexKeys.get(vlist.get(0).key())
					+ " " + vertexKeys.get(vlist.get(1).key()) + " "
					+ vertexKeys.get(vlist.get(2).key()) + " -1\n")
							.getBytes());
				}
				vlist.clear();
				counter++;
			}
			out.write("\t\t] #coordIndex\n".getBytes());
			out.write("\t\tcolorPerVertex FALSE\n".getBytes());
			out.write("\t\tcolor Color {\n".getBytes());
			out.write("\t\t\tcolor [\n".getBytes());
			// list face colors
			counter = 0;
			fItr = mesh.fItr();
			while (fItr.hasNext()) {
				f = fItr.next();
				final int c = f.getColor();
				out.write(("\t\t\t" + (red(c) / 255.0) + " "
						+ (green(c) / 255.0) + " " + (blue(c) / 255.0) + ",\n")
						.getBytes());
				counter++;
			}
			out.write("\t\t\t] #color\n".getBytes());
			out.write("\t\t} #Color\n".getBytes());
			out.write("\t} #IndexedFaceSet\n".getBytes());
			out.write("} #Shape\n".getBytes());
			out.flush();
			out.close();
		} catch (final IOException e) {
		}
	}

	/**
	 *
	 *
	 * @param what
	 * @return
	 */
	public static final int red(final int what) {
		return (what >> 16) & 0xff;
	}

	/**
	 *
	 *
	 * @param what
	 * @return
	 */
	public static final int green(final int what) {
		return (what >> 8) & 0xff;
	}

	/**
	 *
	 *
	 * @param what
	 * @return
	 */
	public static final int blue(final int what) {
		return (what) & 0xff;
	}

	/**
	 *
	 *
	 * @param file
	 * @return
	 * @throws IOException
	 */
	static public OutputStream createOutputStream(final File file)
			throws IOException {
		if (file == null) {
			throw new IllegalArgumentException("file can't be null");
		}
		createDirectories(file);
		OutputStream stream = new FileOutputStream(file);
		if (file.getName().toLowerCase().endsWith(".gz")) {
			stream = new GZIPOutputStream(stream);
		}
		return stream;
	}

	/**
	 *
	 *
	 * @param file
	 */
	static public void createDirectories(final File file) {
		try {
			final String parentName = file.getParent();
			if (parentName != null) {
				final File parent = new File(parentName);
				if (!parent.exists()) {
					parent.mkdirs();
				}
			}
		} catch (final SecurityException se) {
			System.err.println("No permissions to create "
					+ file.getAbsolutePath());
		}
	}

	/**
	 *
	 *
	 * @param mesh
	 * @param stream
	 */
	public static void saveMesh(final HE_Mesh mesh, final OutputStream stream) {
		try {
			final BufferedOutputStream out = new BufferedOutputStream(stream,
					0x20000);
			out.write("#VRML V2.0 utf8\n".getBytes());
			out.write("#Generated by Hemesh Colorizer http://leonnicholls.com\n"
					.getBytes());
			out.write("\n".getBytes());
			out.write("Shape {\n".getBytes());
			out.write("\tappearance Appearance {\n".getBytes());
			out.write("\t\tmaterial Material {\n".getBytes());
			out.write("\t\t}  #Material\n".getBytes());
			out.write("\t} #Appearance\n".getBytes());
			out.write("\tgeometry IndexedFaceSet {\n".getBytes());
			out.write("\t\tcoord  DEF AllCoords Coordinate {\n".getBytes());
			out.write("\t\tpoint [\n".getBytes());
			// list vertices coordinates
			final TLongIntMap vertexKeys = new TLongIntHashMap(10, 0.5f, -1L,
					-1);
			int counter = 0;
			final HE_VertexIterator vItr = mesh.vItr();
			HE_Vertex v;
			while (vItr.hasNext()) {
				v = vItr.next();
				out.write(("\t\t\t" + v.xf() + " " + v.yf() + " " + v.zf() + ",\n")
						.getBytes());
				vertexKeys.put(v.key(), counter);
				counter++;
			}
			out.write("\t\t] #point\n".getBytes());
			out.write("\t\t} #Coordinate\n".getBytes());
			out.write("\t\tcoordIndex [\n".getBytes());
			// list faces vertices indexes
			counter = 0;
			final HE_FaceIterator fItr = mesh.fItr();
			HE_Face f;
			List<HE_Vertex> vlist;
			while (fItr.hasNext()) {
				f = fItr.next();
				vlist = f.getFaceVertices();
				if (vlist.size() == 3) {
					out.write(("\t\t\t" + vertexKeys.get(vlist.get(0).key())
					+ " " + vertexKeys.get(vlist.get(1).key()) + " "
					+ vertexKeys.get(vlist.get(2).key()) + " -1\n")
							.getBytes());
				}
				vlist.clear();
				counter++;
			}
			out.write("\t\t] #coordIndex\n".getBytes());
			out.write("\t} #IndexedFaceSet\n".getBytes());
			out.write("} #Shape\n".getBytes());
			out.flush();
			out.close();
		} catch (final IOException e) {
		}
	}

	/**
	 *
	 *
	 * @param mesh
	 * @param path
	 * @param name
	 */
	public static void saveMesh(final HE_Mesh mesh, final String path,
			final String name) {
		try {
			saveMesh(mesh, createOutputStream(new File(path, name + ".wrl")));
		} catch (final IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 *
	 *
	 * @param mesh
	 * @param path
	 * @param name
	 */
	public static void saveMeshWithVertexColor(final HE_Mesh mesh,
			final String path, final String name) {
		try {
			saveMeshWithVertexColor(mesh, createOutputStream(new File(path,
					name + ".wrl")));
		} catch (final IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 *
	 *
	 * @param mesh
	 * @param stream
	 */
	public static void saveMeshWithVertexColor(final HE_Mesh mesh,
			final OutputStream stream) {
		try {
			final BufferedOutputStream out = new BufferedOutputStream(stream,
					0x20000);
			out.write("#VRML V2.0 utf8\n".getBytes());
			out.write("#Generated by Hemesh Colorizer http://leonnicholls.com\n"
					.getBytes());
			out.write("\n".getBytes());
			out.write("Shape {\n".getBytes());
			out.write("\tappearance Appearance {\n".getBytes());
			out.write("\t\tmaterial Material {\n".getBytes());
			out.write("\t\t}  #Material\n".getBytes());
			out.write("\t} #Appearance\n".getBytes());
			out.write("\tgeometry IndexedFaceSet {\n".getBytes());
			out.write("\t\tcoord  DEF AllCoords Coordinate {\n".getBytes());
			out.write("\t\tpoint [\n".getBytes());
			// list vertices coordinates
			final TLongIntMap vertexKeys = new TLongIntHashMap(10, 0.5f, -1L,
					-1);
			int counter = 0;
			HE_VertexIterator vItr = mesh.vItr();
			HE_Vertex v;
			while (vItr.hasNext()) {
				v = vItr.next();
				out.write(("\t\t\t" + v.xf() + " " + v.yf() + " " + v.zf() + ",\n")
						.getBytes());
				vertexKeys.put(v.key(), counter);
				counter++;
			}
			out.write("\t\t] #point\n".getBytes());
			out.write("\t\t} #Coordinate\n".getBytes());
			out.write("\t\tcoordIndex [\n".getBytes());
			// list faces vertices indexes
			counter = 0;
			final HE_FaceIterator fItr = mesh.fItr();
			HE_Face f;
			List<HE_Vertex> vlist;
			while (fItr.hasNext()) {
				f = fItr.next();
				vlist = f.getFaceVertices();
				if (vlist.size() == 3) {
					out.write(("\t\t\t" + vertexKeys.get(vlist.get(0).key())
					+ " " + vertexKeys.get(vlist.get(1).key()) + " "
					+ vertexKeys.get(vlist.get(2).key()) + " -1\n")
							.getBytes());
				}
				vlist.clear();
				counter++;
			}
			out.write("\t\t] #coordIndex\n".getBytes());
			out.write("\t\tcolorPerVertex TRUE\n".getBytes());
			out.write("\t\tcolor Color {\n".getBytes());
			out.write("\t\t\tcolor [\n".getBytes());
			// list face colors
			counter = 0;
			vItr = mesh.vItr();
			while (vItr.hasNext()) {
				v = vItr.next();
				final int c = v.getColor();
				out.write(("\t\t\t" + (red(c) / 255.0) + " "
						+ (green(c) / 255.0) + " " + (blue(c) / 255.0) + ",\n")
						.getBytes());
				counter++;
			}
			out.write("\t\t\t] #color\n".getBytes());
			out.write("\t\t} #Color\n".getBytes());
			out.write("\t} #IndexedFaceSet\n".getBytes());
			out.write("} #Shape\n".getBytes());
			out.flush();
			out.close();
		} catch (final IOException e) {
		}
	}
}
